home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkCanvPoly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  28.6 KB  |  994 lines

  1. /* 
  2.  * tkCanvPoly.c --
  3.  *
  4.  *    This file implements polygon items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkCanvPoly.c 1.34 96/02/15 18:52:32
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18.  
  19. /*
  20.  * The structure below defines the record for each polygon item.
  21.  */
  22.  
  23. typedef struct PolygonItem  {
  24.     Tk_Item header;        /* Generic stuff that's the same for all
  25.                  * types.  MUST BE FIRST IN STRUCTURE. */
  26.     int numPoints;        /* Number of points in polygon (always >= 3).
  27.                  * Polygon is always closed. */
  28.     int pointsAllocated;    /* Number of points for which space is
  29.                  * allocated at *coordPtr. */
  30.     double *coordPtr;        /* Pointer to malloc-ed array containing
  31.                  * x- and y-coords of all points in polygon.
  32.                  * X-coords are even-valued indices, y-coords
  33.                  * are corresponding odd-valued indices. */
  34.     int width;            /* Width of outline. */
  35.     XColor *outlineColor;    /* Color for outline. */
  36.     GC outlineGC;        /* Graphics context for drawing outline. */
  37.     XColor *fillColor;        /* Foreground color for polygon. */
  38.     Pixmap fillStipple;        /* Stipple bitmap for filling polygon. */
  39.     GC fillGC;            /* Graphics context for filling polygon. */
  40.     int smooth;            /* Non-zero means draw shape smoothed (i.e.
  41.                  * with Bezier splines). */
  42.     int splineSteps;        /* Number of steps in each spline segment. */
  43. } PolygonItem;
  44.  
  45. /*
  46.  * Information used for parsing configuration specs:
  47.  */
  48.  
  49. static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc,
  50.     Tk_CanvasTagsPrintProc, (ClientData) NULL
  51. };
  52.  
  53. static Tk_ConfigSpec configSpecs[] = {
  54.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  55.     "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK},
  56.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  57.     (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK},
  58.     {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL,
  59. #ifdef STk_CODE
  60.        "#f", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
  61. #else
  62.     "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
  63. #endif
  64.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  65.     "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  66.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  67.     (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK},
  68.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  69.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
  70.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  71.     "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  72.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  73.     (char *) NULL, 0, 0}
  74. };
  75.  
  76. /*
  77.  * Prototypes for procedures defined in this file:
  78.  */
  79.  
  80. static void        ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas,
  81.                 PolygonItem *polyPtr));
  82. static int        ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  83.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  84.                 char **argv, int flags));
  85. static int        CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  86.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  87.                 int argc, char **argv));
  88. static void        DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  89.                 Tk_Item *itemPtr,  Display *display));
  90. static void        DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas,
  91.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  92.                 int x, int y, int width, int height));
  93. static int        PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp,
  94.                 Tk_Canvas canvas, Tk_Item *itemPtr,
  95.                 int argc, char **argv));
  96. static int        PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas,
  97.                 Tk_Item *itemPtr, double *rectPtr));
  98. static double        PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  99.                 Tk_Item *itemPtr, double *pointPtr));
  100. static int        PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  101.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  102. static void        ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  103.                 Tk_Item *itemPtr, double originX, double originY,
  104.                 double scaleX, double scaleY));
  105. static void        TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  106.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  107.  
  108. /*
  109.  * The structures below defines the polygon item type by means
  110.  * of procedures that can be invoked by generic item code.
  111.  */
  112.  
  113. Tk_ItemType tkPolygonType = {
  114.     "polygon",                /* name */
  115.     sizeof(PolygonItem),        /* itemSize */
  116.     CreatePolygon,            /* createProc */
  117.     configSpecs,            /* configSpecs */
  118.     ConfigurePolygon,            /* configureProc */
  119.     PolygonCoords,            /* coordProc */
  120.     DeletePolygon,            /* deleteProc */
  121.     DisplayPolygon,            /* displayProc */
  122.     0,                    /* alwaysRedraw */
  123.     PolygonToPoint,            /* pointProc */
  124.     PolygonToArea,            /* areaProc */
  125.     PolygonToPostscript,        /* postscriptProc */
  126.     ScalePolygon,            /* scaleProc */
  127.     TranslatePolygon,            /* translateProc */
  128.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  129.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  130.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  131.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  132.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  133.     (Tk_ItemType *) NULL        /* nextPtr */
  134. };
  135.  
  136. /*
  137.  * The definition below determines how large are static arrays
  138.  * used to hold spline points (splines larger than this have to
  139.  * have their arrays malloc-ed).
  140.  */
  141.  
  142. #define MAX_STATIC_POINTS 200
  143.  
  144. /*
  145.  *--------------------------------------------------------------
  146.  *
  147.  * CreatePolygon --
  148.  *
  149.  *    This procedure is invoked to create a new polygon item in
  150.  *    a canvas.
  151.  *
  152.  * Results:
  153.  *    A standard Tcl return value.  If an error occurred in
  154.  *    creating the item, then an error message is left in
  155.  *    interp->result;  in this case itemPtr is
  156.  *    left uninitialized, so it can be safely freed by the
  157.  *    caller.
  158.  *
  159.  * Side effects:
  160.  *    A new polygon item is created.
  161.  *
  162.  *--------------------------------------------------------------
  163.  */
  164.  
  165. static int
  166. CreatePolygon(interp, canvas, itemPtr, argc, argv)
  167.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  168.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  169.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  170.                      * has been initialized by caller. */
  171.     int argc;                /* Number of arguments in argv. */
  172.     char **argv;            /* Arguments describing polygon. */
  173. {
  174.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  175.     int i;
  176.  
  177.     if (argc < 6) {
  178.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  179.         Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
  180.         itemPtr->typePtr->name,
  181.         " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?\"", (char *) NULL);
  182.     return TCL_ERROR;
  183.     }
  184.  
  185.     /*
  186.      * Carry out initialization that is needed in order to clean
  187.      * up after errors during the the remainder of this procedure.
  188.      */
  189.  
  190.     polyPtr->numPoints = 0;
  191.     polyPtr->pointsAllocated = 0;
  192.     polyPtr->coordPtr = NULL;
  193.     polyPtr->width = 1;
  194.     polyPtr->outlineColor = NULL;
  195.     polyPtr->outlineGC = None;
  196.     polyPtr->fillColor = NULL;
  197.     polyPtr->fillStipple = None;
  198.     polyPtr->fillGC = None;
  199.     polyPtr->smooth = 0;
  200.     polyPtr->splineSteps = 12;
  201.  
  202.     /*
  203.      * Count the number of points and then parse them into a point
  204.      * array.  Leading arguments are assumed to be points if they
  205.      * start with a digit or a minus sign followed by a digit.
  206.      */
  207.  
  208.     for (i = 4; i < (argc-1); i+=2) {
  209.     if ((!isdigit(UCHAR(argv[i][0]))) &&
  210.         ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) {
  211.         break;
  212.     }
  213.     }
  214.     if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) {
  215.     goto error;
  216.     }
  217.  
  218.     if (ConfigurePolygon(interp, canvas, itemPtr, argc-i, argv+i, 0)
  219.         == TCL_OK) {
  220.     return TCL_OK;
  221.     }
  222.  
  223.     error:
  224.     DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  225.     return TCL_ERROR;
  226. }
  227.  
  228. /*
  229.  *--------------------------------------------------------------
  230.  *
  231.  * PolygonCoords --
  232.  *
  233.  *    This procedure is invoked to process the "coords" widget
  234.  *    command on polygons.  See the user documentation for details
  235.  *    on what it does.
  236.  *
  237.  * Results:
  238.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  239.  *
  240.  * Side effects:
  241.  *    The coordinates for the given item may be changed.
  242.  *
  243.  *--------------------------------------------------------------
  244.  */
  245.  
  246. static int
  247. PolygonCoords(interp, canvas, itemPtr, argc, argv)
  248.     Tcl_Interp *interp;            /* Used for error reporting. */
  249.     Tk_Canvas canvas;            /* Canvas containing item. */
  250.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  251.                      * read or modified. */
  252.     int argc;                /* Number of coordinates supplied in
  253.                      * argv. */
  254.     char **argv;            /* Array of coordinates: x1, y1,
  255.                      * x2, y2, ... */
  256. {
  257.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  258.     char buffer[TCL_DOUBLE_SPACE];
  259.     int i, numPoints;
  260.  
  261.     if (argc == 0) {
  262.     for (i = 0; i < 2*polyPtr->numPoints; i++) {
  263.         Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer);
  264.         Tcl_AppendElement(interp, buffer);
  265.     }
  266.     } else if (argc < 6) {
  267.     Tcl_AppendResult(interp,
  268.         "too few coordinates for polygon: must have at least 6",
  269.         (char *) NULL);
  270.     return TCL_ERROR;
  271.     } else if (argc & 1) {
  272.     Tcl_AppendResult(interp,
  273.         "odd number of coordinates specified for polygon",
  274.         (char *) NULL);
  275.     return TCL_ERROR;
  276.     } else {
  277.     numPoints = argc/2;
  278.     if (polyPtr->pointsAllocated <= numPoints) {
  279.         if (polyPtr->coordPtr != NULL) {
  280.         ckfree((char *) polyPtr->coordPtr);
  281.         }
  282.  
  283.         /*
  284.          * One extra point gets allocated here, just in case we have
  285.          * to add another point to close the polygon.
  286.          */
  287.  
  288.         polyPtr->coordPtr = (double *) ckalloc((unsigned)
  289.             (sizeof(double) * (argc+2)));
  290.         polyPtr->pointsAllocated = numPoints+1;
  291.     }
  292.     for (i = argc-1; i >= 0; i--) {
  293.         if (Tk_CanvasGetCoord(interp, canvas, argv[i],
  294.             &polyPtr->coordPtr[i]) != TCL_OK) {
  295.         return TCL_ERROR;
  296.         }
  297.     }
  298.     polyPtr->numPoints = numPoints;
  299.     
  300.     /*
  301.      * Close the polygon if it isn't already closed.
  302.      */
  303.     
  304.     if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0])
  305.         || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) {
  306.         polyPtr->numPoints++;
  307.         polyPtr->coordPtr[argc] = polyPtr->coordPtr[0];
  308.         polyPtr->coordPtr[argc+1] = polyPtr->coordPtr[1];
  309.     }
  310.     ComputePolygonBbox(canvas, polyPtr);
  311.     }
  312.     return TCL_OK;
  313. }
  314.  
  315. /*
  316.  *--------------------------------------------------------------
  317.  *
  318.  * ConfigurePolygon --
  319.  *
  320.  *    This procedure is invoked to configure various aspects
  321.  *    of a polygon item such as its background color.
  322.  *
  323.  * Results:
  324.  *    A standard Tcl result code.  If an error occurs, then
  325.  *    an error message is left in interp->result.
  326.  *
  327.  * Side effects:
  328.  *    Configuration information, such as colors and stipple
  329.  *    patterns, may be set for itemPtr.
  330.  *
  331.  *--------------------------------------------------------------
  332.  */
  333.  
  334. static int
  335. ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags)
  336.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  337.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  338.     Tk_Item *itemPtr;        /* Polygon item to reconfigure. */
  339.     int argc;            /* Number of elements in argv.  */
  340.     char **argv;        /* Arguments describing things to configure. */
  341.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  342. {
  343.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  344.     XGCValues gcValues;
  345.     GC newGC;
  346.     unsigned long mask;
  347.     Tk_Window tkwin;
  348.  
  349.     tkwin = Tk_CanvasTkwin(canvas);
  350.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  351.         (char *) polyPtr, flags) != TCL_OK) {
  352.     return TCL_ERROR;
  353.     }
  354.  
  355.     /*
  356.      * A few of the options require additional processing, such as
  357.      * graphics contexts.
  358.      */
  359.  
  360.     if (polyPtr->width < 1) {
  361.     polyPtr->width = 1;
  362.     }
  363.     if (polyPtr->outlineColor == NULL) {
  364.     newGC = None;
  365.     } else {
  366.     gcValues.foreground = polyPtr->outlineColor->pixel;
  367.     gcValues.line_width = polyPtr->width;
  368.     gcValues.cap_style = CapRound;
  369.     gcValues.join_style = JoinRound;
  370.     mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle;
  371.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  372.     }
  373.     if (polyPtr->outlineGC != None) {
  374.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC);
  375.     }
  376.     polyPtr->outlineGC = newGC;
  377.  
  378.     if (polyPtr->fillColor == NULL) {
  379.     newGC = None;
  380.     } else {
  381.     gcValues.foreground = polyPtr->fillColor->pixel;
  382.     mask = GCForeground;
  383.     if (polyPtr->fillStipple != None) {
  384.         gcValues.stipple = polyPtr->fillStipple;
  385.         gcValues.fill_style = FillStippled;
  386.         mask |= GCStipple|GCFillStyle;
  387.     }
  388.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  389.     }
  390.     if (polyPtr->fillGC != None) {
  391.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC);
  392.     }
  393.     polyPtr->fillGC = newGC;
  394.  
  395.     /*
  396.      * Keep spline parameters within reasonable limits.
  397.      */
  398.  
  399.     if (polyPtr->splineSteps < 1) {
  400.     polyPtr->splineSteps = 1;
  401.     } else if (polyPtr->splineSteps > 100) {
  402.     polyPtr->splineSteps = 100;
  403.     }
  404.  
  405.     ComputePolygonBbox(canvas, polyPtr);
  406.     return TCL_OK;
  407. }
  408.  
  409. /*
  410.  *--------------------------------------------------------------
  411.  *
  412.  * DeletePolygon --
  413.  *
  414.  *    This procedure is called to clean up the data structure
  415.  *    associated with a polygon item.
  416.  *
  417.  * Results:
  418.  *    None.
  419.  *
  420.  * Side effects:
  421.  *    Resources associated with itemPtr are released.
  422.  *
  423.  *--------------------------------------------------------------
  424.  */
  425.  
  426. static void
  427. DeletePolygon(canvas, itemPtr, display)
  428.     Tk_Canvas canvas;            /* Info about overall canvas widget. */
  429.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  430.     Display *display;            /* Display containing window for
  431.                      * canvas. */
  432. {
  433.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  434.  
  435.     if (polyPtr->coordPtr != NULL) {
  436.     ckfree((char *) polyPtr->coordPtr);
  437.     }
  438.     if (polyPtr->fillColor != NULL) {
  439.     Tk_FreeColor(polyPtr->fillColor);
  440.     }
  441.     if (polyPtr->fillStipple != None) {
  442.     Tk_FreeBitmap(display, polyPtr->fillStipple);
  443.     }
  444.     if (polyPtr->outlineColor != NULL) {
  445.     Tk_FreeColor(polyPtr->outlineColor);
  446.     }
  447.     if (polyPtr->outlineGC != None) {
  448.     Tk_FreeGC(display, polyPtr->outlineGC);
  449.     }
  450.     if (polyPtr->fillGC != None) {
  451.     Tk_FreeGC(display, polyPtr->fillGC);
  452.     }
  453. }
  454.  
  455. /*
  456.  *--------------------------------------------------------------
  457.  *
  458.  * ComputePolygonBbox --
  459.  *
  460.  *    This procedure is invoked to compute the bounding box of
  461.  *    all the pixels that may be drawn as part of a polygon.
  462.  *
  463.  * Results:
  464.  *    None.
  465.  *
  466.  * Side effects:
  467.  *    The fields x1, y1, x2, and y2 are updated in the header
  468.  *    for itemPtr.
  469.  *
  470.  *--------------------------------------------------------------
  471.  */
  472.  
  473. static void
  474. ComputePolygonBbox(canvas, polyPtr)
  475.     Tk_Canvas canvas;            /* Canvas that contains item. */
  476.     PolygonItem *polyPtr;        /* Item whose bbox is to be
  477.                      * recomputed. */
  478. {
  479.     double *coordPtr;
  480.     int i;
  481.  
  482.     coordPtr = polyPtr->coordPtr;
  483.     polyPtr->header.x1 = polyPtr->header.x2 = *coordPtr;
  484.     polyPtr->header.y1 = polyPtr->header.y2 = coordPtr[1];
  485.  
  486.     for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints;
  487.         i++, coordPtr += 2) {
  488.     TkIncludePoint((Tk_Item *) polyPtr, coordPtr);
  489.     }
  490.  
  491.     /*
  492.      * Expand bounding box in all directions to account for the outline,
  493.      * which can stick out beyond the polygon.  Add one extra pixel of
  494.      * fudge, just in case X rounds differently than we do.
  495.      */
  496.  
  497.     i = (polyPtr->width+1)/2 + 1;
  498.     polyPtr->header.x1 -= i;
  499.     polyPtr->header.x2 += i;
  500.     polyPtr->header.y1 -= i;
  501.     polyPtr->header.y2 += i;
  502. }
  503.  
  504. /*
  505.  *--------------------------------------------------------------
  506.  *
  507.  * TkFillPolygon --
  508.  *
  509.  *    This procedure is invoked to convert a polygon to screen
  510.  *    coordinates and display it using a particular GC.
  511.  *
  512.  * Results:
  513.  *    None.
  514.  *
  515.  * Side effects:
  516.  *    ItemPtr is drawn in drawable using the transformation
  517.  *    information in canvas.
  518.  *
  519.  *--------------------------------------------------------------
  520.  */
  521.  
  522. void
  523. TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC)
  524.     Tk_Canvas canvas;            /* Canvas whose coordinate system
  525.                      * is to be used for drawing. */
  526.     double *coordPtr;            /* Array of coordinates for polygon:
  527.                      * x1, y1, x2, y2, .... */
  528.     int numPoints;            /* Twice this many coordinates are
  529.                      * present at *coordPtr. */
  530.     Display *display;            /* Display on which to draw polygon. */
  531.     Drawable drawable;            /* Pixmap or window in which to draw
  532.                      * polygon. */
  533.     GC gc;                /* Graphics context for drawing. */
  534.     GC outlineGC;            /* If not None, use this to draw an
  535.                      * outline around the polygon after
  536.                      * filling it. */
  537. {
  538.     XPoint staticPoints[MAX_STATIC_POINTS];
  539.     XPoint *pointPtr;
  540.     XPoint *pPtr;
  541.     int i;
  542.  
  543.     /*
  544.      * Build up an array of points in screen coordinates.  Use a
  545.      * static array unless the polygon has an enormous number of points;
  546.      * in this case, dynamically allocate an array.
  547.      */
  548.  
  549.     if (numPoints <= MAX_STATIC_POINTS) {
  550.     pointPtr = staticPoints;
  551.     } else {
  552.     pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
  553.     }
  554.  
  555.     for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
  556.     Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x,
  557.         &pPtr->y);
  558.     }
  559.  
  560.     /*
  561.      * Display polygon, then free up polygon storage if it was dynamically
  562.      * allocated.
  563.      */
  564.  
  565.     if (gc != None) {
  566.     XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex,
  567.         CoordModeOrigin);
  568.     }
  569.     if (outlineGC != None) {
  570.     XDrawLines(display, drawable, outlineGC, pointPtr,
  571.         numPoints, CoordModeOrigin);
  572.     }
  573.     if (pointPtr != staticPoints) {
  574.     ckfree((char *) pointPtr);
  575.     }
  576. }
  577.  
  578. /*
  579.  *--------------------------------------------------------------
  580.  *
  581.  * DisplayPolygon --
  582.  *
  583.  *    This procedure is invoked to draw a polygon item in a given
  584.  *    drawable.
  585.  *
  586.  * Results:
  587.  *    None.
  588.  *
  589.  * Side effects:
  590.  *    ItemPtr is drawn in drawable using the transformation
  591.  *    information in canvas.
  592.  *
  593.  *--------------------------------------------------------------
  594.  */
  595.  
  596. static void
  597. DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height)
  598.     Tk_Canvas canvas;            /* Canvas that contains item. */
  599.     Tk_Item *itemPtr;            /* Item to be displayed. */
  600.     Display *display;            /* Display on which to draw item. */
  601.     Drawable drawable;            /* Pixmap or window in which to draw
  602.                      * item. */
  603.     int x, y, width, height;        /* Describes region of canvas that
  604.                      * must be redisplayed (not used). */
  605. {
  606.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  607.  
  608.     if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) {
  609.     return;
  610.     }
  611.  
  612.     /*
  613.      * If we're stippling then modify the stipple offset in the GC.  Be
  614.      * sure to reset the offset when done, since the GC is supposed to be
  615.      * read-only.
  616.      */
  617.  
  618.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  619.     Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC);
  620.     }
  621.  
  622.     if (!polyPtr->smooth) {
  623.     TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints,
  624.         display, drawable, polyPtr->fillGC, polyPtr->outlineGC);
  625.     } else {
  626.     int numPoints;
  627.     XPoint staticPoints[MAX_STATIC_POINTS];
  628.     XPoint *pointPtr;
  629.  
  630.     /*
  631.      * This is a smoothed polygon.  Display using a set of generated
  632.      * spline points rather than the original points.
  633.      */
  634.  
  635.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  636.     if (numPoints <= MAX_STATIC_POINTS) {
  637.         pointPtr = staticPoints;
  638.     } else {
  639.         pointPtr = (XPoint *) ckalloc((unsigned)
  640.             (numPoints * sizeof(XPoint)));
  641.     }
  642.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  643.         polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
  644.         (double *) NULL);
  645.     if (polyPtr->fillGC != None) {
  646.         XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr,
  647.             numPoints, Complex, CoordModeOrigin);
  648.     }
  649.     if (polyPtr->outlineGC != None) {
  650.         XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr,
  651.             numPoints, CoordModeOrigin);
  652.     }
  653.     if (pointPtr != staticPoints) {
  654.         ckfree((char *) pointPtr);
  655.     }
  656.     }
  657.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  658.     XSetTSOrigin(display, polyPtr->fillGC, 0, 0);
  659.     }
  660. }
  661.  
  662. /*
  663.  *--------------------------------------------------------------
  664.  *
  665.  * PolygonToPoint --
  666.  *
  667.  *    Computes the distance from a given point to a given
  668.  *    polygon, in canvas units.
  669.  *
  670.  * Results:
  671.  *    The return value is 0 if the point whose x and y coordinates
  672.  *    are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
  673.  *    point isn't inside the polygon then the return value is the
  674.  *    distance from the point to the polygon.
  675.  *
  676.  * Side effects:
  677.  *    None.
  678.  *
  679.  *--------------------------------------------------------------
  680.  */
  681.  
  682.     /* ARGSUSED */
  683. static double
  684. PolygonToPoint(canvas, itemPtr, pointPtr)
  685.     Tk_Canvas canvas;        /* Canvas containing item. */
  686.     Tk_Item *itemPtr;        /* Item to check against point. */
  687.     double *pointPtr;        /* Pointer to x and y coordinates. */
  688. {
  689.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  690.     double *coordPtr, distance;
  691.     double staticSpace[2*MAX_STATIC_POINTS];
  692.     int numPoints;
  693.  
  694.     if (!polyPtr->smooth) {
  695.     distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints,
  696.         pointPtr);
  697.     } else {
  698.     /*
  699.      * Smoothed polygon.  Generate a new set of points and use them
  700.      * for comparison.
  701.      */
  702.     
  703.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  704.     if (numPoints <= MAX_STATIC_POINTS) {
  705.         coordPtr = staticSpace;
  706.     } else {
  707.         coordPtr = (double *) ckalloc((unsigned)
  708.             (2*numPoints*sizeof(double)));
  709.     }
  710.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  711.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  712.         coordPtr);
  713.     distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr);
  714.     if (coordPtr != staticSpace) {
  715.         ckfree((char *) coordPtr);
  716.     }
  717.     }
  718.     if (polyPtr->outlineColor != NULL) {
  719.     distance -= polyPtr->width/2.0;
  720.     if (distance < 0) {
  721.         distance = 0;
  722.     }
  723.     }
  724.     return distance;
  725. }
  726.  
  727. /*
  728.  *--------------------------------------------------------------
  729.  *
  730.  * PolygonToArea --
  731.  *
  732.  *    This procedure is called to determine whether an item
  733.  *    lies entirely inside, entirely outside, or overlapping
  734.  *    a given rectangular area.
  735.  *
  736.  * Results:
  737.  *    -1 is returned if the item is entirely outside the area
  738.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  739.  *    inside the given area.
  740.  *
  741.  * Side effects:
  742.  *    None.
  743.  *
  744.  *--------------------------------------------------------------
  745.  */
  746.  
  747.     /* ARGSUSED */
  748. static int
  749. PolygonToArea(canvas, itemPtr, rectPtr)
  750.     Tk_Canvas canvas;        /* Canvas containing item. */
  751.     Tk_Item *itemPtr;        /* Item to check against polygon. */
  752.     double *rectPtr;        /* Pointer to array of four coordinates
  753.                  * (x1, y1, x2, y2) describing rectangular
  754.                  * area.  */
  755. {
  756.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  757.     double *coordPtr, rect2[4], halfWidth;
  758.     double staticSpace[2*MAX_STATIC_POINTS];
  759.     int numPoints, result;
  760.  
  761.     /*
  762.      * Handle smoothed polygons by generating an expanded set of points
  763.      * against which to do the check.
  764.      */
  765.  
  766.     if (polyPtr->smooth) {
  767.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  768.     if (numPoints <= MAX_STATIC_POINTS) {
  769.         coordPtr = staticSpace;
  770.     } else {
  771.         coordPtr = (double *) ckalloc((unsigned)
  772.             (2*numPoints*sizeof(double)));
  773.     }
  774.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  775.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  776.         coordPtr);
  777.     } else {
  778.     numPoints = polyPtr->numPoints;
  779.     coordPtr = polyPtr->coordPtr;
  780.     }
  781.  
  782.     if (polyPtr->width <= 1) {
  783.     /*
  784.      * The outline of the polygon doesn't stick out, so we can
  785.      * do a simple check.
  786.      */
  787.  
  788.     result = TkPolygonToArea(coordPtr, numPoints, rectPtr);
  789.     } else {
  790.     /*
  791.      * The polygon has a wide outline, so the check is more complicated.
  792.      * First, check the line segments to see if they overlap the area.
  793.      */
  794.  
  795.     result = TkThickPolyLineToArea(coordPtr, numPoints, 
  796.         (double) polyPtr->width, CapRound, JoinRound, rectPtr);
  797.     if (result >= 0) {
  798.         goto done;
  799.     }
  800.  
  801.     /*
  802.      * There is no overlap between the polygon's outline and the
  803.      * rectangle.  This means either the rectangle is entirely outside
  804.      * the polygon or entirely inside.  To tell the difference,
  805.      * see whether the polygon (with 0 outline width) overlaps the
  806.      * rectangle bloated by half the outline width.
  807.      */
  808.  
  809.     halfWidth = polyPtr->width/2.0;
  810.     rect2[0] = rectPtr[0] - halfWidth;
  811.     rect2[1] = rectPtr[1] - halfWidth;
  812.     rect2[2] = rectPtr[2] + halfWidth;
  813.     rect2[3] = rectPtr[3] + halfWidth;
  814.     if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) {
  815.         result = -1;
  816.     } else {
  817.         result = 0;
  818.     }
  819.     }
  820.  
  821.     done:
  822.     if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) {
  823.     ckfree((char *) coordPtr);
  824.     }
  825.     return result;
  826. }
  827.  
  828. /*
  829.  *--------------------------------------------------------------
  830.  *
  831.  * ScalePolygon --
  832.  *
  833.  *    This procedure is invoked to rescale a polygon item.
  834.  *
  835.  * Results:
  836.  *    None.
  837.  *
  838.  * Side effects:
  839.  *    The polygon referred to by itemPtr is rescaled so that the
  840.  *    following transformation is applied to all point
  841.  *    coordinates:
  842.  *        x' = originX + scaleX*(x-originX)
  843.  *        y' = originY + scaleY*(y-originY)
  844.  *
  845.  *--------------------------------------------------------------
  846.  */
  847.  
  848. static void
  849. ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY)
  850.     Tk_Canvas canvas;            /* Canvas containing polygon. */
  851.     Tk_Item *itemPtr;            /* Polygon to be scaled. */
  852.     double originX, originY;        /* Origin about which to scale rect. */
  853.     double scaleX;            /* Amount to scale in X direction. */
  854.     double scaleY;            /* Amount to scale in Y direction. */
  855. {
  856.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  857.     double *coordPtr;
  858.     int i;
  859.  
  860.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  861.         i++, coordPtr += 2) {
  862.     *coordPtr = originX + scaleX*(*coordPtr - originX);
  863.     coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  864.     }
  865.     ComputePolygonBbox(canvas, polyPtr);
  866. }
  867.  
  868. /*
  869.  *--------------------------------------------------------------
  870.  *
  871.  * TranslatePolygon --
  872.  *
  873.  *    This procedure is called to move a polygon by a given
  874.  *    amount.
  875.  *
  876.  * Results:
  877.  *    None.
  878.  *
  879.  * Side effects:
  880.  *    The position of the polygon is offset by (xDelta, yDelta),
  881.  *    and the bounding box is updated in the generic part of the
  882.  *    item structure.
  883.  *
  884.  *--------------------------------------------------------------
  885.  */
  886.  
  887. static void
  888. TranslatePolygon(canvas, itemPtr, deltaX, deltaY)
  889.     Tk_Canvas canvas;            /* Canvas containing item. */
  890.     Tk_Item *itemPtr;            /* Item that is being moved. */
  891.     double deltaX, deltaY;        /* Amount by which item is to be
  892.                      * moved. */
  893. {
  894.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  895.     double *coordPtr;
  896.     int i;
  897.  
  898.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  899.         i++, coordPtr += 2) {
  900.     *coordPtr += deltaX;
  901.     coordPtr[1] += deltaY;
  902.     }
  903.     ComputePolygonBbox(canvas, polyPtr);
  904. }
  905.  
  906. /*
  907.  *--------------------------------------------------------------
  908.  *
  909.  * PolygonToPostscript --
  910.  *
  911.  *    This procedure is called to generate Postscript for
  912.  *    polygon items.
  913.  *
  914.  * Results:
  915.  *    The return value is a standard Tcl result.  If an error
  916.  *    occurs in generating Postscript then an error message is
  917.  *    left in interp->result, replacing whatever used
  918.  *    to be there.  If no error occurs, then Postscript for the
  919.  *    item is appended to the result.
  920.  *
  921.  * Side effects:
  922.  *    None.
  923.  *
  924.  *--------------------------------------------------------------
  925.  */
  926.  
  927. static int
  928. PolygonToPostscript(interp, canvas, itemPtr, prepass)
  929.     Tcl_Interp *interp;            /* Leave Postscript or error message
  930.                      * here. */
  931.     Tk_Canvas canvas;            /* Information about overall canvas. */
  932.     Tk_Item *itemPtr;            /* Item for which Postscript is
  933.                      * wanted. */
  934.     int prepass;            /* 1 means this is a prepass to
  935.                      * collect font information;  0 means
  936.                      * final Postscript is being created. */
  937. {
  938.     char string[100];
  939.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  940.  
  941.     /*
  942.      * Fill the area of the polygon.
  943.      */
  944.  
  945.     if (polyPtr->fillColor != NULL) {
  946.     if (!polyPtr->smooth) {
  947.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  948.             polyPtr->numPoints);
  949.     } else {
  950.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  951.             polyPtr->numPoints);
  952.     }
  953.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) {
  954.         return TCL_ERROR;
  955.     }
  956.     if (polyPtr->fillStipple != None) {
  957.         Tcl_AppendResult(interp, "eoclip ", (char *) NULL);
  958.         if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple)
  959.             != TCL_OK) {
  960.         return TCL_ERROR;
  961.         }
  962.         if (polyPtr->outlineColor != NULL) {
  963.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  964.         }
  965.     } else {
  966.         Tcl_AppendResult(interp, "eofill\n", (char *) NULL);
  967.     }
  968.     }
  969.  
  970.     /*
  971.      * Now draw the outline, if there is one.
  972.      */
  973.  
  974.     if (polyPtr->outlineColor != NULL) {
  975.     if (!polyPtr->smooth) {
  976.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  977.         polyPtr->numPoints);
  978.     } else {
  979.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  980.         polyPtr->numPoints);
  981.     }
  982.  
  983.     sprintf(string, "%d setlinewidth\n", polyPtr->width);
  984.     Tcl_AppendResult(interp, string,
  985.         "1 setlinecap\n1 setlinejoin\n", (char *) NULL);
  986.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor)
  987.         != TCL_OK) {
  988.         return TCL_ERROR;
  989.     }
  990.     Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  991.     }
  992.     return TCL_OK;
  993. }
  994.